import socketserver
import logging
import threading

FORMAT = "%(asctime)s\t%(processName)s\t%(threadName)s\t%(levelname)s\t%(message)s"
logging.basicConfig(level=logging.INFO, format=FORMAT, datefmt='%H:%M:%S')


class EchoHandler(socketserver.BaseRequestHandler):
    # 定义成类属性，这样所有的handler实例，共用类的属性,能获取到所有连接的客户端
    clients = {}

    def setup(self) -> None:
        super().setup()
        self.event = threading.Event()
        # 每一个连接过来，都是单独的一个hanlde，不会累记客户端
        # self.clients = {}
        self.clock = threading.Lock()

    def handle(self) -> None:
        super().handle()

        with self.clock:
            self.clients[self.client_address] = self.request

        while not self.event.is_set():
            try:
                data = self.request.recv(1024)
            except ConnectionAbortedError as e:
                logging.error(e)
                data = b''
            if not data or data == b'quit':
                print('{}:{} quits'.format(*self.client_address))
                break
            msg = data.decode('gbk')

            with self.clock:
                for c in self.clients.values():
                    c.send('{} ~~~~'.format(msg).encode('gbk'))

            logging.info(data)
            logging.info(self.clients.values())

    def finish(self) -> None:
        super().finish()
        self.event.set()
        with self.clock:
            self.clients.pop(self.client_address)


def main():
    ipaddr = ('127.0.0.1', 9999)
    server = socketserver.ThreadingTCPServer(ipaddr, EchoHandler)
    threading.Thread(target=server.serve_forever, name='forever').start()

    while True:
        cmd = input('>>>>')
        if cmd == 'quit':
            server.shutdown()  # 等待客户端断开以后，才会停止，使用server_close会报错
            break
        print(threading.enumerate())


if __name__ == '__main__':
    main()


# 做的不错, 各种情况都考虑进去了
